package org.example.analysis.service;

import lombok.extern.slf4j.Slf4j;
import org.example.analysis.model.config.ExportConfig;
import org.example.analysis.model.entity.EntryPointInfo;
import org.example.analysis.model.entity.JavaClassInfo;
import org.example.analysis.model.entity.JavaMethodInfo;
import org.example.analysis.model.entity.ProjectInfo;
import org.example.analysis.service.dataobj.ProjectDataObject;
import org.apache.commons.lang3.StringUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

import java.io.File;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 报告生成服务
 */
@Slf4j
public class ReportGenerateService {
    private final CodeAnalysisDbService codeAnalysisDbService = new CodeAnalysisDbService();
    private final TemplateEngine templateEngine;

    public ReportGenerateService() {
        // 初始化Thymeleaf模板引擎
        templateEngine = new TemplateEngine();
        
        // 配置模板解析器
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        resolver.setTemplateMode(TemplateMode.TEXT);
        resolver.setPrefix("/templates/");
        resolver.setSuffix(".md");
        resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
        resolver.setCacheable(false);
        
        templateEngine.setTemplateResolver(resolver);
    }

    /**
     * 生成分析报告
     */
    public void generateReport(ExportConfig config) {
        if (config == null || StringUtils.isEmpty(config.getProjectName())) {
            throw new IllegalArgumentException("项目名称不能为空");
        }

        try {
            // 1. 获取报告数据
            ProjectInfo projectInfo = getReportData(config);
            if (projectInfo == null) {
                throw new IllegalArgumentException("获取项目数据失败：" + config.getProjectName());
            }

            // 2. 准备模板上下文
            Context context = new Context();
            context.setVariable("projectName", projectInfo.getProjectName());
            context.setVariable("currentTime", new Date());
            
            // 项目概览数据
            context.setVariable("totalClasses", projectInfo.getClassInfoList().size());
            context.setVariable("totalMethods", getTotalMethods(projectInfo));
            context.setVariable("totalCodeLines", getTotalCodeLines(projectInfo));
            context.setVariable("totalEntryPoints", projectInfo.getEntryPointInfoList().size());
            
            // 复杂度分析数据
            context.setVariable("averageComplexity", String.format("%d", getAverageMethodComplexity(projectInfo)));
            context.setVariable("maxComplexity", getMaxMethodComplexity(projectInfo));
            context.setVariable("minComplexity", getMinMethodComplexity(projectInfo));
            context.setVariable("highComplexityMethodCount", getHighComplexityMethodCount(projectInfo, config.getMinMethodComplexity()));
            
            // 高复杂度类列表
            List<Map<String, Object>> highComplexityClasses = new ArrayList<>();
            for (JavaClassInfo classInfo : projectInfo.getClassInfoList()) {
                // 如果类的平均复杂度或高复杂度方法比例超过阈值，则认为是高复杂度类
                if (classInfo.getComplexityScore()>config.getMinClassComplexity()) {
                    Map<String, Object> classData = new HashMap<>();
                    classData.put("className", classInfo.getClassName());
                    classData.put("methodCount", 0);
                    classData.put("totalLines", classInfo.getCodeLines());
                    classData.put("complexityScore", classInfo.getComplexityScore());
                    classData.put("classDesc",classInfo.getClassDesc());
                    highComplexityClasses.add(classData);
                }
            }
            
            // 按总复杂度降序排序
            highComplexityClasses.sort((a, b) -> ((Integer) b.get("complexityScore")).compareTo((Integer) a.get("complexityScore")));
            context.setVariable("highComplexityClasses", highComplexityClasses);
            
            // 高复杂度方法列表
            List<Map<String, Object>> highComplexityMethods = new ArrayList<>();
            for (JavaClassInfo classInfo : projectInfo.getClassInfoList()) {
                for (JavaMethodInfo methodInfo : classInfo.getMethods()) {
                    Integer complexity = methodInfo.getComplexityScore();
                    if (complexity != null && complexity >= config.getMinMethodComplexity()) {
                        Map<String, Object> method = new HashMap<>();
                        method.put("className", classInfo.getClassName());
                        method.put("methodName", methodInfo.getMethodName());
                        method.put("complexityScore", complexity);
                        method.put("codeLines", methodInfo.getCodeLines());
                        method.put("improvement", getComplexityImprovement(complexity));
                        highComplexityMethods.add(method);
                    }
                }
            }
            
            // 按复杂度降序排序
            highComplexityMethods.sort((a, b) -> ((Integer)b.get("complexityScore")).compareTo((Integer)a.get("complexityScore")));
            context.setVariable("highComplexityMethods", highComplexityMethods);
            
            // 入口点分析数据
            List<Map<String, Object>> entryPoints = new ArrayList<>();
            for (EntryPointInfo entryPoint : projectInfo.getEntryPointInfoList()) {
                Integer complexity = entryPoint.getComplexity();
                if (complexity != null && complexity >= config.getMinEntryPointComplexity()) {
                    Map<String, Object> entry = new HashMap<>();
                    entry.put("className", entryPoint.getClassName());
                    entry.put("methodName", entryPoint.getMethodName());
                    entry.put("entryType", entryPoint.getEntryType());
                    entry.put("complexity", complexity);
                    entry.put("improvement", getComplexityImprovement(complexity.doubleValue()));
                    entryPoints.add(entry);
                }
            }
            context.setVariable("entryPoints", entryPoints);

            // 3. 生成报告文件
            String outputPath = String.format("reports/%s_analysis_report_%s.md", 
                    projectInfo.getProjectName(), 
                    new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()));
            
            File outputDir = new File("reports");
            if (!outputDir.exists()) {
                outputDir.mkdirs();
            }
            
            // 4. 使用模板引擎生成报告
            try (FileWriter writer = new FileWriter(outputPath, StandardCharsets.UTF_8)) {
                templateEngine.process("report", context, writer);
                log.info("报告生成成功：{}", outputPath);
            }
            
        } catch (Exception e) {
            log.error("生成报告失败", e);
            throw new RuntimeException("生成报告失败: " + e.getMessage());
        }
    }

    /**
     * 获取复杂度改进建议
     */
    private String getComplexityImprovement(double complexity) {
        if (complexity > 15) {
            return "建议拆分方法，降低复杂度";
        } else if (complexity > 10) {
            return "建议优化代码结构";
        } else if (complexity > 7) {
            return "可以考虑优化";
        }
        return "复杂度正常";
    }

    /**
     * 获取总方法数
     */
    private int getTotalMethods(ProjectInfo projectInfo) {
        return projectInfo.getClassInfoList().stream()
                .mapToInt(cls -> cls.getMethods().size())
                .sum();
    }

    /**
     * 获取总代码行数
     */
    private int getTotalCodeLines(ProjectInfo projectInfo) {
        return projectInfo.getClassInfoList().stream()
                .flatMap(cls -> cls.getMethods().stream())
                .mapToInt(method -> method.getCodeLines() != null ? method.getCodeLines() : 0)
                .sum();
    }

    /**
     * 获取平均方法复杂度
     */
    private Integer getAverageMethodComplexity(ProjectInfo projectInfo) {
        List<Integer> complexities = projectInfo.getClassInfoList().stream()
                .flatMap(cls -> cls.getMethods().stream())
                .map(JavaMethodInfo::getComplexityScore)
                .filter(complexity -> complexity != null)
                .collect(Collectors.toList());
        
        if (complexities.isEmpty()) {
            return 0;
        }
        
        return (int) complexities.stream()
                .mapToInt(Integer::intValue)
                .average()
                .orElse(0.0);
    }

    /**
     * 获取最大方法复杂度
     */
    private Integer getMaxMethodComplexity(ProjectInfo projectInfo) {
        return projectInfo.getClassInfoList().stream()
                .flatMap(cls -> cls.getMethods().stream())
                .map(JavaMethodInfo::getComplexityScore)
                .filter(complexity -> complexity != null)
                .mapToInt(Integer::intValue)
                .max()
                .orElse(0);
    }

    /**
     * 获取最小方法复杂度
     */
    private Integer getMinMethodComplexity(ProjectInfo projectInfo) {
        return projectInfo.getClassInfoList().stream()
                .flatMap(cls -> cls.getMethods().stream())
                .map(JavaMethodInfo::getComplexityScore)
                .filter(complexity -> complexity != null)
                .mapToInt(Integer::intValue)
                .min()
                .orElse(0);
    }

    /**
     * 获取高复杂度方法数量
     */
    private int getHighComplexityMethodCount(ProjectInfo projectInfo, double threshold) {
        return (int) projectInfo.getClassInfoList().stream()
                .flatMap(cls -> cls.getMethods().stream())
                .map(JavaMethodInfo::getComplexityScore)
                .filter(complexity -> complexity != null && complexity >= threshold)
                .count();
    }

    /**
     * 获取类的复杂度
     */
    private double getClassComplexity(JavaClassInfo classInfo) {
        if (classInfo.getMethods() == null || classInfo.getMethods().isEmpty()) {
            return 0.0;
        }
        
        // 使用所有方法的complexityScore总和作为类的复杂度
        return classInfo.getMethods().stream()
                .map(JavaMethodInfo::getComplexityScore)
                .filter(complexity -> complexity != null)
                .mapToDouble(Integer::doubleValue)
                .sum();
    }

    /**
     * 获取类的复杂度改进建议
     */
    private String getClassComplexityImprovement(double complexity) {
        if (complexity > 50) {
            return "建议拆分类，职责过重";
        } else if (complexity > 30) {
            return "建议重构，优化类结构";
        } else if (complexity > 20) {
            return "可以考虑优化";
        }
        return "复杂度正常";
    }

    /**
     * 获取报告数据
     */
    private ProjectInfo getReportData(ExportConfig config) {
        if (config == null || StringUtils.isEmpty(config.getProjectName())) {
            throw new IllegalArgumentException("项目名称不能为空");
        }

        try {
            // 1. 获取项目基本信息
            ProjectInfo projectInfo = codeAnalysisDbService.getProjectInfo(config.getProjectName());
            if (projectInfo == null) {
                throw new IllegalArgumentException("项目不存在：" + config.getProjectName());
            }

            // 2. 获取入口点信息
            List<EntryPointInfo> entryPoints = codeAnalysisDbService.getEntryPoints(config.getProjectName());
            if (entryPoints != null) {
                // 根据最小复杂度过滤
                entryPoints = entryPoints.stream()
                    .filter(ep -> {
                        if (ep.getComplexity() == null) {
                            return false;
                        }
                        return ep.getComplexity() >= config.getMinEntryPointComplexity();
                    })
                    .collect(Collectors.toList());
                projectInfo.setEntryPointInfoList(entryPoints);
            }

            // 3. 获取类信息
            List<JavaClassInfo> classes = codeAnalysisDbService.getAllClasses(config.getProjectName());
            if (classes != null) {
                // 根据配置过滤类
                classes = classes.stream()
                    .filter(cls -> {
                        // 过滤测试类
                        if (!config.isIncludeTestClasses() && cls.isTestClass()) {
                            return false;
                        }
                        // 过滤内部类
                        if (!config.isIncludeInnerClasses() && cls.isInnerClass()) {
                            return false;
                        }
                        return true;
                    })
                    .collect(Collectors.toList());
                List<JavaMethodInfo> methodInfos=codeAnalysisDbService.getAllMethods(config.getProjectName());
                // 使用类名和方法名的组合作为key
                Map<String,List<JavaMethodInfo>> methodMap = methodInfos.stream()
                    .collect(Collectors.groupingBy(method -> method.getClassName()));
                
                for(JavaClassInfo cls: classes){
                    if(methodMap.containsKey(cls.getClassName())){
                        cls.setMethods(methodMap.get(cls.getClassName()));
                    }
                }
                projectInfo.setClassInfoList(classes);
            }

            return projectInfo;
        } catch (Exception e) {
            log.error("获取报告数据失败", e);
            throw new RuntimeException("获取报告数据失败: " + e.getMessage());
        }
    }
} 